/*
 * File Name: httpstuff.h
 *
 * Group Members: Cassie Chin (cassiechin9793@gmail.com)
 *                Stephen Smetana (stephensmetana11@gmail.com)
 *                Logan Widick (logan.widick@gmail.com)
 *
 * File Description: 
 *
 *
 */

#ifndef HTTP_STUFF_H
#define HTTP_STUFF_H
// Size of strings in the HTTPMsg
#define BUFFER_SIZE 1024

//special content length constants
#define CONTENT_LENGTH_NOT_SET -1
#define CHUNKED_LENGTH -2

//uncomment to use proxy:proxy_port/dest:dest_port/path/on/dest
#define USE_FIRST_FOLDER_AS_PROXY_LOC 1

#define CHUNK_SIZE 256
#define NUMBER_BUFFER_SIZE 256

//error codes for message send and receive
#define FILE_CLOSE -3
#define PARSE_ERROR -4

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
/**
 * A HeaderListNode stores a header from http.
 */
typedef struct HeaderListNode {
	char *name;
	char *value;
	struct HeaderListNode *next;
} HeaderListNode;

/**
 * A headerlist stores a list of headers in an http message
 */
typedef struct HeaderList {
	HeaderListNode *head;
	HeaderListNode *tail;
} HeaderList;

/**
 * Keeps track of the http state
 */
typedef enum HTTPState {
	FIRSTLINE = 0, //!< FIRSTLINE
	HEADERS = 1, //!< HEADERS
	BODY = 2, //!< BODY
	TRAILERS = 3,
	END = 4, //!< END
} HTTPState;

/**
 * Stores the required information for a certain response code.
 */
typedef struct HTTPResponseCode {
	/** the numeric (machine-readable) status code) */
	int num;

	/** the human readable code */
	char *desc;

	/** whether or not we can have a body */
	bool canHaveBody;
} HTTPResponseCode;

/**
 * Represents the data inside an http message.
 */
typedef struct HTTPMsg {
	/** Whether this is a REQUEST or a RESPONSE */
	bool isRequest;

	/** The method of the request */
	char *method;

	/** A list of headers and their values */
	HeaderList *headerList;

	HeaderList *trailerList;

	/** The resource to obtain, according to the request uri */
	char *resource;

	/** The port */
	char *port;

	/** the path to the file */
	char *path;

	/** the host */
	char *host;

	/** The reason phrase (if a response) */
	char *reasonPhrase;

	/** The version of HTTP to use */
	float version;

	/** The state of the parsing */
	HTTPState state;

	/** The status code (responses) */
	int statusCode;

	/** the content length we go with */
	int contentLength;

	/** Pointer to the file */
	FILE *fileptr;

} HTTPMsg;

/**
 * Constructor for a header list
 * @return a new header list
 */
HeaderList *new_HeaderList();

/**
 * Destructor for a header list.
 * @param list the headerlist to free.
 */
void delete_HeaderList(HeaderList *list);

/**
 * Adds a header to the list. As the strings are copied, it is the caller's responsiblity to free them.
 * @param list the headerlist instance
 * @param name The name of the new header (will be copied)
 * @param value The value of the new header (will be copied)
 */
void HeaderList_addHeader(HeaderList *list, char *name, char *value);
void HeaderList_addToLastHeader(HeaderList *list, char *value);

/**
 * Gets the value of the header in the header list.
 * @param list the headerlist instance
 * @param name The name of the header
 * @return
 * 		The value of the header, or NULL if the header does not exist.
 * 		THIS IS NOT A COPY SO DO NOT FREE.
 */
char* HeaderList_getHeader(HeaderList *list, char *name);

/**
 * Constructor for a new HTTPMsg.
 * @return a new HTTPMsg.
 */
HTTPMsg *new_HTTPMsg();

/**
 * Destructor for a HTTPMsg.
 * @param msg the HTTPMsg to free.
 */
void delete_HTTPMsg(HTTPMsg *msg);

/**
 * Sends a message.
 * @param msg the message to send
 * @param fd the low-level file descriptor to send with
 * @return 0 on success; something negative on failure.
 */
int HTTPMsg_sendMsg(HTTPMsg *msg, int fd);

/**
 * Attempts to read in a message from a file descriptor
 * @param msg The HTTPMsg instance to read into
 * @param fd the file descriptor to read from
 * @param useFirstFolderAsLoc If true, use the first folder as the location of the target site.
 * @return 0 on success; something negative on failure.
 */
int HTTPMsg_doParsing(HTTPMsg *msg, int fd, bool useFirstFolderAsLoc);

/**
 * A simple method for printing out the headers and starting line of an HTTPMsg.
 * Does not print out body or trailers.
 * @param msg the HTTPMsg
 * @param theFile the file* to print to.
 */
void HTTPMsg_print(HTTPMsg *msg, FILE* theFile);

/**
 * Removes a header from the list.
 * @param list the headerlist instance
 * @param key the key (name of header) to remove.
 */
void HeaderList_removeHeaderByKey(HeaderList *list, char *key);

/**
 * Gets the target info from the first folder in a URL.
 * Examples:
 * /www.example.com/file.html will set host=www.example.com, port=80
 * /www.example.com:8080/file.html will set host=www.example.com, port=8080
 * @param msg the HTTP message.
 * @param url the url.
 * @return
 * 		A pointer to the string starting AFTER the first folder. DO NOT FREE.
 * 		The two above examples will both return "/file.html"
 */
char* HTTPMsg_getTargetInfoFromFirstFolderInURL(HTTPMsg *msg, char *url);

/**
 * Extracts the portion of the URL for the host and port.
 * Examples:
 * http://www.google.com/file.html will return a string starting with "www.google.com"
 * http://www.google.com:8080/file.html will return a string starting with "www.google.com:8080"
 * www.google.com:80/file.html will return a string starting with "www.google.com:80"
 * www.google.com:80/file.html
 * @param msg
 * @param theresource
 * @return a new string for the portion of the URL that contains the host and port.
 */
char* HTTPMsg_extractHostPortPortionOfURL(HTTPMsg *msg, char *theresource);

/**
 * Sets the HTTPMsg to use a given URL for making the host, port, path, etc.
 * @param msg the HTTPMsg.
 * @param theresource the URL to use.
 */
void HTTPMsg_useResource(HTTPMsg *msg, char *theresource,
		bool useFirstFolderAsLoc);

/**
 * Use the "Host" header to set the host and port info.
 * @param msg the HTTPMsg.
 */
void HTTPMsg_useHost(HTTPMsg *msg);

/**
 * Tries every way to load the host, path, and port info for a message.
 * @param msg
 */
void HTTPMsg_loadHostPathAndPort(HTTPMsg *msg, bool useFirstFolderAsLoc);

/**
 * Returns true if the URL contains an argument section.
 * If the URL contains an argument section, we probably should not cache it. 
 * @param msg the message
 * @param theresource the URL to test.
 * @return true if an argument section is present; otherwise false. 
 */
bool HTTPMsg_doesResourceContainArgSection(HTTPMsg *msg, char *theresource);

/**
 * Attempts to guess if the message is dynamic. 
 * It is assumed that a URL is not dynamic unless it contains an argument section. 
 * @param msg the HTTPMsg. 
 */
bool HTTPMsg_isDynamic(HTTPMsg *msg, bool useFirstFolderAsLoc);

/**
 * Convenience function for obtaining the resource represented by the message. 
 * @param msg the HTTPMsg
 * @return a new char* containing the resource. 
 */
char* HTTPMsg_getResource(HTTPMsg *msg);

/**
 * Prepends a string to the message's resource.
 * @param msg
 * @param strToAppend
 */
void HTTPMsg_prependStringToResource(HTTPMsg *msg, char *strToAppend);

/**
 * Attempts to find a path relative to the executable's directory to save the file in the HTTPMsg.
 * @param msg The HTTPMsg instance
 * @param useFirstFolderAsLoc
 * 		If true, the first folder in the message is the name of the destination site.
 * @return
 * 		the path relative to the executable's directory,
 * 		or NULL if the content is dynamic or if a path could not be made for any other reason.
 */
char* HTTPMsg_findFilePath(HTTPMsg *msg, bool useFirstFolderAsLoc);

/**
 * \struct FilePointerSet
 * A FilePointerSet contains a read descriptor and a write descriptor for a socket.
 */
typedef struct FilePointerSet {
	int inFile;
	int outFile;
} FilePointerSet;

/**
 * Opens a client connection given the port, ip, and a pointer to a FilePointerSet to be filled
 * @param PORT the port # as a string
 * @param IP the IP address to connect to
 * @param ptrSet the pointer to the FilePointerSet to fill.
 * @return 0 on success, something negative on fail.
 */
int openClientConnection(char *PORT, char *IP, FilePointerSet *ptrSet);

/**
 * Extracts the path portion of a URL.
 * Examples:
 * http://www.google.com/folder/file.html will obtain /folder/file.html
 * www.google.com/folder/file.html will obtain /folder/file.html
 * google.com:8080/folder/file.html will obtain /folder/file.html
 * @param msg
 * @param theresource
 * @return the path portion of the url.
 */
char* HTTPMsg_extractPathPortionOfURL(HTTPMsg *msg, char *theresource);

/**
 * Determines if the http message is text.
 * @param msg the message
 * @return true if it should be filtered; otherwise false
 */
bool HTTPMsg_shouldFilter(HTTPMsg *msg);

#endif
